package com.flying.acls.domain.service;

import com.flying.acls.domain.context.ContextStringValueResolver;
import com.flying.acls.domain.context.ExpressionContext;
import com.flying.acls.model.*;
import com.flying.acls.model.PermsExpr;
import com.flying.acls.model.ResExpr;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

/**
 * Default implementation for Matcher.
 * for String , we using Ant style.
 * for Integer, we using bit operator to support.
 */
public class AntStyleMatcher implements Matcher {
    private ContextStringValueResolver resolver;

    private PathMatcher pathMatcher;

    public AntStyleMatcher(ContextStringValueResolver resolver) {
        this.resolver = resolver;
        this.pathMatcher = new AntPathMatcher();
    }

    @Override
    public boolean match(ExpressionContext context, ResExpr config, ResExpr access) {
        if (config.getType() != access.getType()) return false;
        String ce = resolveExpression(context, config.getExprType(), config.getExpression());
        String ae = resolveExpression(context, access.getExprType(), access.getExpression());
        return pathMatcher.isPattern(ce) ? pathMatcher.match(ce, ae) : ce.equals(ae);
    }


    @Override
    public boolean match(ExpressionContext context, SidExpr config, SidExpr access) {
        if (config.getType() != access.getType()) return false;
        String ce = resolveExpression(context, config.getExprType(), config.getExpression());
        String ae = resolveExpression(context, access.getExprType(), access.getExpression());
        return pathMatcher.isPattern(ce) ? pathMatcher.match(ce, ae) : ce.equals(ae);
    }

    @Override
    public boolean match(ExpressionContext context, PermsExpr config, PermsExpr access) {
        return config.getType() == access.getType() && ((config.getMask() & access.getMask()) == access.getMask());
    }

    private String resolveExpression(ExpressionContext context, ExprType type, String expression) {
        String resolved;
        switch (type) {
            case DIRECT:
                resolved = expression;
                break;
            case VAR:
                resolved = resolver.resolveStringValue(context, expression);
                break;
            default:
                throw new RuntimeException("Unsupported expression type!" + type.toString());
        }
        return resolved;
    }
}
